<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>粒子掉落</title>
    <style>
        *{
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body{
            background-color: #333;
            overflow: hidden;
        }
        span.check{
            display: inline-block;
            font-family: Arial, Helvetica, sans-serif;
            font-size: 40px;
        }
    </style>
</head>
<body>
    <canvas id="canvas"></canvas>
    <script>
        let canvas = document.querySelector("#canvas");
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
        let ctx = canvas.getContext('2d');
        let textCanvas = document.createElement("canvas");
        let tctx = textCanvas.getContext('2d');
        let pixs = [];
        let index = 0;
        let colors = ['#ffa502','#ff6348','#ff4757','#2ed573','#1e90ff','#3742fa']
        let strs = ['我喜欢你','真的喜欢你','看不惯我','又干不掉我的样子'];
        let particalArr = [];

        let size = 40;      // 字体尺寸，实际绘制*5倍
        let radius = 2;     // 粒子半径，暂时未发现优化

        class Partical{
            constructor(x,y){
                this.x = x;
                this.y = y;
                this.vy = Math.random() - 1.5;
                this.vx = 0.5 - Math.random();
                this.g = 0.05;
                this.color = colors[Math.random() * colors.length | 0];
                this.wait = 40; // 等待时长
            }
            update(){
                if(this.wait < 0){
                    // 更改2可以改变初速度
                    this.x += this.vx * 2;
                    this.y += this.vy * 2;
                    this.vy += this.g;
                }
                this.wait--;
            }
            draw(){
                ctx.beginPath();
                ctx.arc(this.x,this.y,radius,0,Math.PI * 2)
                ctx.fillStyle = this.color;
                ctx.fill();
            }
        }

        let ch = str => {
            let span = document.createElement("span");
            span.className = "check";
            span.textContent = str;
            document.body.appendChild(span);
            let w = span.clientWidth;
            let h = span.clientHeight;
            document.body.removeChild(span);
            return [w,h];
        }
        // 文字转换成图片
        let textdata = i => {
            let textarea = ch(strs[i]);
            textCanvas.width = textarea[0];
            textCanvas.height = textarea[1];
            tctx.clearRect(0,0,textCanvas.width,textCanvas.height);
            tctx.font = `${size}px Arial`;
            tctx.fillText(strs[i],0,size);
            return tctx.getImageData(0,0,textCanvas.width,textCanvas.height);
        }
        let init = () => {
            pixs = textdata(index % strs.length);
            for(let i = 0;i < pixs.data.length / 4;i++){
                if(pixs.data[i*4+3] != 0){
                    // 5控制放大倍数
                    // x = (i % textCanvas.width) * 5 + (canvas.width - textCanvas.width * 5) / 2;
                    // y = (i / textCanvas.width | 0) * 5 + (canvas.height - textCanvas.height * 5) / 2;
                    x = (i % textCanvas.width) * 5  + (canvas.width - textCanvas.width * size * 5 / 40) / 2;
                    y = (i / textCanvas.width | 0) * 5 + (canvas.height - textCanvas.height * size * 5 / 40) / 2;
                    particalArr.push(new Partical(x,y));
                }
            }
            index++;
        }
        let draw = () => {
            ctx.clearRect(0,0,canvas.width,canvas.height);
            for(let i = 0;i < particalArr.length;i++){
                particalArr[i].update();
                particalArr[i].draw();
                if(particalArr[i].y > canvas.height){
                    // 删除粒子
                    particalArr.splice(i,1);
                }
                if(particalArr.length == 0){
                    init();
                }
            }
            requestAnimationFrame(draw);
        }
        init();
        requestAnimationFrame(draw);
    </script>
</body>
</html>